package com.jel.WiKikonwledge.Dao;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.arangodb.ArangoCursor;
import com.arangodb.ArangoDBException;
import com.arangodb.ArangoDatabase;
import com.arangodb.velocypack.VPackParser;
import com.arangodb.velocypack.VPackSlice;
import com.fasterxml.jackson.databind.deser.std.JsonLocationInstantiator;
import com.jel.WiKikonwledge.bean.cont;
import com.jel.WiKikonwledge.bean.graph;
import com.jel.WiKikonwledge.bean.user;

import java.util.*;

import static com.jel.WiKikonwledge.Util.To_Arangodb.getConnection;

/**
 * @author curbert:jiangenlai
 * @description
 * @date 2022-05-24 18:32:55
 * @PACKAGE_NAME:com.jel.WiKikonwledge.Dao
 */
public class GetSonlmpl implements GetSon{
    public static String getnames(JSONObject elem){
        if(elem.containsKey("labels")){
            if(elem.getJSONObject("labels").containsKey("zh-cn")){
                return elem.getJSONObject("labels").getString("zh-cn");
            }
            else if(elem.getJSONObject("labels").containsKey("en")){
                return elem.getJSONObject("labels").getString("en");
            }
            else{
                return "null";
            }
        }
        return "null";
    }
    public static String getdesc(JSONObject elem){
        if(elem.containsKey("descs")){
            if(elem.getJSONObject("descs").containsKey("zh-cn")){
                return elem.getJSONObject("descs").getString("zh-cn");
            }else if(elem.getJSONObject("descs").containsKey("en")){
                return elem.getJSONObject("descs").getString("en");
            }else{
                return "null";
            }
        }
        return "null";
    }
    public static JSONObject trans(Object elem){
        return JSON.parseObject(elem.toString());
    }
    public static List<Object> sog(List<Object> arr){
        HashSet<Object> hash = new HashSet<>();
        HashSet<Object> hashset = new HashSet<>();
        for (Object ey: arr
        ) {
            JSONObject every = trans(ey);
            JSONArray edges = every.getJSONArray("edges");
            JSONArray vertices = every.getJSONArray("vertices");

            for (Object i: edges
            ) {
                hash.add(i);
            }
            for (Object j: vertices
            ) {
                hashset.add(j);
            }
        }
        List<Object> ert = new ArrayList<>();
        ert.add(hash);
        ert.add(hashset);
        return ert;
    }
    @Override
    public JSONObject getall(String id) {
        ArangoDatabase db = getConnection();
        JSONObject answer = null;
        try {
            String query = "for each in user\n" +
                    "filter each._key=='"+id+"'\n" +
                    "return each";
            ArangoCursor<VPackSlice> cursor = db.query(query, VPackSlice.class);
            VPackParser parser = new VPackParser.Builder().build();
            List<Object> list = new ArrayList<>();
            cursor.forEachRemaining(aDocument -> {
                list.add(JSONObject.parse(parser.toJson(aDocument)));
            });
            answer = new JSONObject();

            for (int i = 0; i < list.size(); i++) {
                List<Object> obj1 = new ArrayList<>();
                List<Object> obj2 = new ArrayList<>();
                String name;
                JSONObject jsonObject = (JSONObject) JSONObject.parse(String.valueOf(list.get(i)));
                String key = jsonObject.getString("_key");
//                System.out.println(key);
                //寻找名字
                JSONObject names = jsonObject.getJSONObject("labels");
                boolean flag1 = names.containsKey("ja");
                if (flag1 != true) {
                    boolean flag2 = names.containsKey("en");
                    if (flag2 != true) {
                        name = "null";
                    } else {
                        name = names.getString("en");
                    }
                } else {
                    name = names.getString("ja");
                }
//                System.out.println(name);
                JSONObject res = jsonObject.getJSONObject("claims");
                JSONObject des = jsonObject.getJSONObject("descs");
                String descs;
                boolean flag4 = des.containsKey("zh-cn");
                if (flag4 != true) {
                    boolean flag5 = des.containsKey("en");
                    if (flag5 != true) {
                        descs = "null";
                    } else {
                        descs = des.getString("en");
                    }
                } else {
                    descs = des.getString("zh-cn");
                }
//                System.out.println(descs);
                answer.put("name", key + ";" + name+";"+descs);

                //寻找P31对应的实例。
                try {
                    boolean flag3 = res.containsKey("P31");
                    if (flag3 == true) {
                        List<Object> ear1 = (List<Object>) JSONObject.parse(String.valueOf(res.getJSONArray("P31")));
                        for (int j = 0; j < ear1.size(); j++) {
                            JSONObject result = (JSONObject) JSONObject.parse(String.valueOf(ear1.get(j)));
                            JSONObject result1 = result.getJSONObject("val");
                            JSONObject result2 = result1.getJSONObject("dv");
                            String tag = result2.getString("val");
                            obj1.add(tag);
                        }
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                //寻找直接子类

                try {
                    boolean flag = res.containsKey("P279");
                    if (flag) {
//                        System.out.println(JSONObject.parse(String.valueOf(res.getJSONArray("P279"))));
                        List<Object> ear = (List<Object>) JSONObject.parse(String.valueOf(res.getJSONArray("P279")));
                        for (int j = 0; j < ear.size(); j++) {
                            JSONObject result = (JSONObject) JSONObject.parse(String.valueOf(ear.get(j)));
                            JSONObject result1 = result.getJSONObject("val");
                            JSONObject result2 = result1.getJSONObject("dv");
                            String tag = result2.getString("val");
//                            System.out.println(tag);
                            obj2.add(tag);
                        }
                    }

                } catch (JSONException e) {
                    e.printStackTrace();
                }
                answer.put("P31", obj2);
                answer.put("P279", obj1);
            }

        } catch (ArangoDBException e) {
            System.err.println("Failed to execute query. " + e.getMessage());
        }
        return answer;
    }

    @Override
    public ArrayList<cont> gObjects(String id) {
        JSONObject value = new JSONObject();
        ArrayList<cont> arr = null;
        List<Object> list = new ArrayList<>();
        try {
            String query = "FOR v,e,p IN 1..1 INBOUND '"+id+"' GRAPH 'example'\n" +
                    "options {bfs: true,uniqueVertices:'glocal'}\n" +
                    "filter p.edges[*].prop ALL == \"P31\"\n" +
                    "return p";
            curous(list, query);
            arr = new ArrayList<>();
            for (Object a : list) {
                JSONObject b = JSONObject.parseObject(a.toString());
                JSONArray m = b.getJSONArray("vertices");
//                JSONArray edges = b.getJSONArray("edges");
                //对于每个边遍历循环根据每一条边的的情况建立一个对象类。
                for (Object elem: m){
                    JSONObject data = trans(elem);
                    if(data.getString("_id").equals(id)) {
                        continue;
                    }else {
                        cont every = new cont();
                        every.setLabel(getnames(data));
                        if(!getnames(data).equals("null"))
                            arr.add(every);
                    }
                }
            }
        } catch (ArangoDBException e) {
            e.printStackTrace();
        }
        return arr;
    }

    @Override
    public user data(String id) {
        user ent = new user();
        GetSon fd = new GetSonlmpl();
        JSONObject element = fd.value(id);
        ent.setName(getnames(element));
        ent.setDesc(getdesc(element));

        List<Object> arr = fd.tree(id,"P279");
        int P279 = 0;
        int P279_ = 0;
        JSONObject struct = new JSONObject();
        struct.put("name",ent.getName());
        struct.put("id",id);
        JSONArray arr0 = new JSONArray();
        for (Object elem :
                arr) {
            JSONObject ll = JSON.parseObject(elem.toString());
            JSONArray vec = JSON.parseArray(ll.getString("vertices"));
            JSONArray edges = JSON.parseArray(ll.getString("edges"));
            if(edges.size() == 1){
                P279++;
            }else if(edges.size()==2){
                P279_++;
            }
            for (Object each :
                    edges) {
                JSONObject edge = trans(each);
                String from = edge.getString("_from");
                JSONObject nodes = new JSONObject();
                for (Object voc :
                        vec) {
                    JSONObject node = trans(voc);
                    if(node.getString("_id").equals(from)){
                        nodes.put("name",getnames(node));
                        nodes.put("id",from);
                    }
                    JSONArray arr1 = new JSONArray();
                    for (Object each2 :
                            edges) {
                        JSONObject edge2 = trans(each2);
                        String from2 = edge2.getString("_from");
                        JSONObject nodes2 = new JSONObject();
                        for (Object voc2 :
                                vec) {
                            JSONObject node2 = trans(voc2);
                            if(node2.getString("_id").equals(from2)){
                                nodes2.put("name",getnames(node2));
                                nodes2.put("id",from2);
                            }
                            JSONArray arr2 =new JSONArray();
                            for (Object each3 :
                                    edges) {
                                JSONObject edge3 = trans(each3);
                                String from3 = edge3.getString("_from");
                                JSONObject nodes3 = new JSONObject();
                                for (Object voc3 :
                                        vec) {
                                    JSONObject node3 = trans(voc3);
                                    if(node3.getString("_id").equals(from3)){
                                        nodes3.put("name",getnames(node3));
                                        nodes3.put("id",from3);
                                    }
                                }
                                arr2.add(nodes3);
                            }
                            if(arr2.size()>1)
                                nodes2.put("children",arr2);
                        }
                        arr1.add(nodes2);
                    }
                    if(arr1.size()>1)
                        nodes.put("children",arr1);
                }
                arr0.add(nodes);
            }
        }

        if(arr0.size()>1) {
            struct.put("children", arr0);
        }
        ent.setStruct(struct);
        ent.setP279len(P279);
        ent.setP279_len(P279_);
        List<Object> arr2 = fd.tree(id,"P31");
        int P31 = 0;
        int P31_ = 0;
        for (Object elem :
                arr2) {
            JSONObject ll = JSON.parseObject(elem.toString());
            JSONArray edges2 = JSON.parseArray(ll.getString("edges"));
            if(edges2.size() == 1){
                P31++;
            }else if(edges2.size()==2){
                P31_++;
            }
        }
        ent.setP31len(P31);
        ent.setP31_len(P31_);
        List<Object> data_father = fd.father(id,"P279");
        String father = "";
        for (Object elem :
                data_father) {
            JSONObject every = trans(elem);
            String each_name = getnames(every);
            father+=each_name+";";
        }
        if(father.length()<=4)father = "null";
        ent.setFather(father);
        return ent;
    }

    @Override
    public List<Object> tree(String id, String name){
        List<Object> list = new ArrayList<>();
        try {
            String query = "FOR v,e,p IN 1..2 INBOUND '"+id+"' GRAPH 'example'\n" +
                    "options {bfs: true,uniqueVertices:'glocal'}\n" +
                    "filter p.edges[*].prop ALL == \""+name+"\"\n" +
                    "return p";
            curous(list, query);
        }catch (ArangoDBException e){
            e.printStackTrace();
        }
        return list;
    }

    @Override
    public JSONObject value(String id) {
        JSONObject values = new JSONObject();
        List<Object> list = new ArrayList<>();
        try{
            String query = "for each in entity\n" +
                    "filter each['_id'] == \""+id+"\"\n" +
                    "return each";
            curous(list, query);
            for (Object elem :
                    list) {
                values = JSON.parseObject(elem.toString());
            }
            return values;
        }catch (ArangoDBException e){
            e.printStackTrace();
        }
        return values;
    }
    @Override
    public List<Object> father(String id, String name){
        List<Object> list = new ArrayList<>();
        try {
            String query = "FOR v,e,p IN 1..1 OUTBOUND '"+id+"' GRAPH 'example'\n" +
                    "options {bfs: true,uniqueVertices:'glocal'}\n" +
                    "filter p.edges[*].prop ALL == \""+name+"\"\n" +
                    "return p";
            curous(list, query);
        }catch (ArangoDBException e){
            e.printStackTrace();
        }
        return list;
    }

    private void curous(List<Object> list, String query) {
        ArangoDatabase db = getConnection();
        ArangoCursor<VPackSlice> cursor = db.query(query, VPackSlice.class);
        VPackParser parser = new VPackParser.Builder().build();
        cursor.forEachRemaining(aDocument -> {
            list.add(JSONObject.parse(parser.toJson(aDocument)));
        });
    }
    public List<Object> geturn(String id, String name){
        List<Object> list = new ArrayList<>();
        try {
            String query = "FOR v,e,p IN 1..1 INBOUND '"+id+"' GRAPH 'example'\n" +
                    "options {bfs: true,uniqueVertices:'glocal'}\n" +
                    "filter p.edges[*].prop ALL == \""+name+"\"\n" +
                    "return v";
            curous(list, query);
        }catch (ArangoDBException e){
            e.printStackTrace();
        }
        return list;
    }
    public int counter = 2;
    public graph get_list(String id,int count_end,int count){
        graph graphs = new graph();
        List<Object> arr = geturn(id,"P279");
        if(arr.size()==0) {
            return null;
        }else{
            count++;
            if(count==count_end){
                return null;
            }
            List<graph> graph_ = new ArrayList<>();
            for (Object obj: arr
            ) {
                JSONObject vec = trans(obj);
                graphs.setName(getnames(vec));
                graphs.setId(vec.getString("_id"));
                get_list(vec.getString("_id"),count_end=2,count);
                graph_.add(graphs);
            }
            graphs.setChidren(graph_);
        }
        return graphs;
    }
}
